-
-
Notifications
You must be signed in to change notification settings - Fork 921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Custom Request Classes using type annotations #930
Conversation
I like this approach but I am a FastAPI user, and I wonder how this could be interfaced there. I assume I would want specific mounts to be handled with my custom request, and not sure if typing is a convinent way. |
Thanks. I don't think this fits with the general approach in Starlette, and introspecting the annotated types is a bit brittle. (Eg. it can break if using generators.) It's feasible that we could support customising the request class, but I think it'd make sense to talk over the design first if so. |
Sounds good to me. It was easier to show the idea than describe it in this case, and I intended this for discussion, so I don't mind closing. |
After experimenting with this, I started to think that offering custom request classes for any arbitrary handler is a powerful and uncommon feature that users are likely to take advantage of. Further, I suspect that changing the request object would be the first obvious thing for users to do, especially when they are unfamiliar with the inner workings of Starlette and they want something other than default behavior. In the discussion about modifying the As the framework is already using dependency injection for the request object, it seems like a natural place for users to specify what to inject. But I was also thinking about making an argument that the |
We're not using dependency injection for the request instance. I think the only place we're introspecting function signatures is the |
I see. If that's the case, then customizing the request object, if it's something that is desirable to do, most likely makes sense in the Routes as well, I think. Alternately, you could also make it so users could specify tooling there instead of swapping the whole request class. For instance, your request-parsing customizability suggestion could go there? It's also true that allowing people to customize the request may offer so much freedom and extensibility that people would use it for things that are better solved elsewhere, such as authentication or data validation and then their implementations could end up too strictly wedded to a particular implementation of the |
This PR is a proof-of-concept exploring support for custom request classes in Starlette (related issues: #715, #388). I wanted to open this PR as a discussion point: there are certainly other ways to implement custom request classes in Starlette.
To use a custom request class under the changes here, you can simply provide a custom request class type annotation for your request handler.
Here's an example:
Results can be seen here:
Changes
request
arg type annotation to instantiate custom request classes.Notes
starlette.middleware.errors
has not been changed.TypeError
if there is a type annotation for therequest
arg and that annotation is not a subclass ofstarlette.requests.Request
.Discussion
I am unsure how people will respond to this proposal. I had a couple of other ideas, but this one seemed ergonomic for end users because it's a small code change, and allows adding any custom request class for any particular endpoint where one is desired. I have tried to break down some of the pros and cons below.
Pros
Cons
"request"
, which means this wouldn't work:def a_handler(req: CustomRequest):
because arg-name is not "request". (We could alternately look at first arg and pull annotation for it)def a_handler(req: List[str])
or something that's not callable; another way to say this is that it takes advantage of the fact that the type annotation is a class definition.